﻿using Business.Uin;
using CommonTool;
using Models.WebChat;
using Newtonsoft.Json;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net.WebSockets;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Web;
using System.Web.Mvc;
using System.Web.WebSockets;

namespace WeChat.Handlers
{
    public static class SocketContextHandler
    {
        private static CancellationToken cancellationToken;
        private static UinInfoManager _UinManager = null;
        private static MessageInfoManager _MessageInfoManager = null;
        private static UinGroupInfoManager _UinGroupManager = null;
        private static UinSocketManager _UinSocketManager = null;

        private static Task taskTimer = null;
        static SocketContextHandler()
        {
            cancellationToken = new CancellationToken();
            _UinManager = new UinInfoManager();
            _MessageInfoManager = new MessageInfoManager();
            _UinGroupManager = new UinGroupInfoManager();
            _UinSocketManager = new UinSocketManager();
            taskTimer = Task.Run(() =>
            {
                while (true)
                {
                    Thread.Sleep(10000);
                    //时间过了整五分钟
                    if (Convert.ToInt32(DateTime.Now.ToString("mmss")) % 500 == 0)
                    {
                        SendNotifyMessage(100000, new MessageInfo
                        {
                            Content = $"当前 {DateTime.Now.ToString("yyyy-MM-dd HH:mm")},共 {_UinSocketManager.Count()} 人在线。",
                            Send_uin = 100000//系统发出
                        }, cancellationToken);
                    }
                }
            }, cancellationToken);
        }

        public static async Task WebSocketRequestHandler(AspNetWebSocketContext SocketContext)
        {
            try
            {
                var uinId = Convert.ToInt32(HttpContext.Current.Request["uinid"]);

                //保存链接的socket
                var uinSocket = new UinSocket { UinId = uinId, Socket = SocketContext.WebSocket };
                _UinSocketManager.Remove(uinId);
                _UinSocketManager.Add(uinSocket);
                //添加到所有分组(默认一个分组)
                _UinGroupManager.AddUinGroupInfo(uinId, 100004);
                //通知所有更新列表
                SendNotifyUpdateList(uinId, cancellationToken);
                //通知上线
                SendNotifyMessage(uinId, new MessageInfo
                {
                    Content = $"{_UinManager.GetUinInfoById(uinId).Uin_name} 上线了！",
                    Send_uin = 100000//系统发出
                }, cancellationToken);
                //接收监听
                while (uinSocket.Socket.State == System.Net.WebSockets.WebSocketState.Open)
                {
                    try
                    {
                        ArraySegment<byte> buffer = new ArraySegment<byte>(new byte[2048]);
                        WebSocketReceiveResult result = await uinSocket.Socket.ReceiveAsync(buffer, cancellationToken);
                        if (result.MessageType == WebSocketMessageType.Close)
                        {
                            _UinSocketManager.Remove(uinSocket);
                            //通知下线
                            SendNotifyMessage(100000, new MessageInfo
                            {
                                Content = $"{_UinManager.GetUinInfoById(uinId).Uin_name} 下线了！",
                                Send_uin = 100000
                            }, cancellationToken);
                        }
                        else
                        {

                            var megContent = Encoding.UTF8.GetString(buffer.ToArray(), 0, result.Count);
                            var requestContent = JsonConvert.DeserializeObject<ConnectContext>(megContent);
                            MessageHandler(uinId, uinSocket, requestContent);
                        }
                    }
                    catch (Exception ex)
                    {
                        //Log
                        Logger.Log(ex.Message + ex.StackTrace);
                    }
                }
            }
            catch (Exception ex)
            {
                //Log
                Logger.Log(ex.Message + ex.StackTrace);
            }
        }
        private static void MessageHandler(int uinId, UinSocket uinSocket, ConnectContext requestContent)
        {
            //接收并处理消息
            if (requestContent.Action.Equals("msg"))
            {
                //发来的消息包含 toUin 和 Content 内容
                var message = JsonConvert.DeserializeObject<MessageInfo>(requestContent.Content.ToString());
                message.Send_uin = uinId;
                var uinInfo = _UinManager.GetUinInfoById(message.To_uin);
                var socketList = new List<UinSocket>();
                var uinIdList = new List<int>();
                //如果是发送到群组，则 toUin 遍历改为组内各个用的 uin ,from_uin 为 groupUin
                if (uinInfo.Uin_type == UinType.GROUP)
                {
                    message.From_uin = uinInfo.Id;
                    uinIdList.AddRange(_UinGroupManager.GetUinuseridList(message.From_uin));
                    socketList = _UinSocketManager.GetUinSocketListByUinIdList(uinIdList.ToArray());
                }
                //如果发给个人，from_uin 跟sendUin一致
                else if (uinInfo.Uin_type == UinType.USER)
                {
                    uinIdList.Add(uinInfo.Id);
                    message.From_uin = message.Send_uin;
                    socketList = _UinSocketManager.GetUinSocketListByUinIdList(uinInfo.Id);
                }
                //发消息到人
                uinIdList.ForEach(toId =>
                {
                    if (toId != uinId)
                    {
                        var msg = Serializer.Clone(message);
                        msg.To_uin = toId;
                        msg.Id = _MessageInfoManager.AddMessageInfo(msg);
                        //保存消息到消息列表
                        var userSocketList = socketList?.Where(us => us.UinId == toId);
                        //给当前在线人发消息
                        SendMessage(userSocketList?.FirstOrDefault()?.Socket, new ConnectContext { Action = "msg", Content = msg }, cancellationToken);
                    }
                });
            }
            //设置消息为已读
            else if (requestContent.Action.Equals("readed"))
            {
                _MessageInfoManager.SetMessageReaded(Convert.ToInt32(requestContent.Content));
            }
            //获取未读消息
            else if (requestContent.Action.Equals("unread"))
            {
                _MessageInfoManager.GetMessageInfoListByFromUinId(Convert.ToInt32(requestContent.Content), uinId).ForEach(msg =>
                {
                    SendMessage(uinSocket.Socket, new ConnectContext { Action = "msg", Content = msg }, cancellationToken);
                });
            }
        }

        private static void SendNotify(int uinId, Action<UinInfo> actNotify)
        {
            var userGroupList = _UinGroupManager.GetUingroupidList(uinId);
            var groupInfoList = _UinManager.GetUinInfoListById(userGroupList.ToArray());
            groupInfoList.ForEach(g =>
            {
                actNotify.Invoke(g);
            });
        }

        /// <summary>
        /// 发送通知消息到群
        /// 上下线提示、定时提示
        /// </summary>
        /// <param name="context"></param>
        /// <param name="cancellationToken"></param>
        private static void SendNotifyMessage(int uinId, MessageInfo message, CancellationToken cancellationToken)
        {

            SendNotify(uinId, g =>
            {
                var uinIdList = _UinGroupManager.GetUinuseridList(g.Id);
                var socketList = _UinSocketManager.GetUinSocketListByUinIdList(uinIdList.ToArray());
                message.From_uin = g.Id;
                socketList?.ForEach(us =>
                {
                    message.To_uin = us.UinId;
                    SendMessage(us.Socket, new ConnectContext
                    {
                        Action = "msg",
                        Content = message
                    }, cancellationToken);
                });
            });

        }
        private static void SendNotifyUpdateList(int uinId, CancellationToken cancellationToken)
        {
            SendNotify(uinId, g =>
            {
                var uinIdList = _UinGroupManager.GetUinuseridList(g.Id);
                var socketList = _UinSocketManager.GetUinSocketListByUinIdList(uinIdList.ToArray());
                socketList?.ForEach(us =>
                {
                    SendMessage(us.Socket, new ConnectContext { Action = "updatelist", Content = "" }, cancellationToken);
                });
            });

        }

        private static void SendMessage(WebSocket Socket, ConnectContext context, CancellationToken cancellationToken)
        {
            try
            {
                Socket?.SendAsync(new ArraySegment<byte>(Encoding.UTF8.GetBytes(JsonConvert.SerializeObject(context))), WebSocketMessageType.Text, true, cancellationToken);
            }
            catch (Exception ex)
            {
                //Log
                Logger.Log(ex.Message + ex.StackTrace);
            }
        }
    }
}